#!/usr/bin/python
# -*- coding: utf-8 -*-
#
#   signstl - generate an stl file based upon input usign OpenScad. 
#   Copyright (C) Brendan M. Sleight, et al. <bms.stl#barwap.com>
#   Including parts of the OpenSCAD Library (Catarina Mota, Elmo Mäntynen)
#   *  Copyright (C) 2009  Catarina Mota
#   *  Copyright (C) 2010  Elmo Mäntynen
#   *
#   *  License: LGPL 2.1 or later
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.



import os
import tempfile
import zipfile
from subprocess import Popen, PIPE
from optparse import OptionParser


def includeRoundedBox():
    return """
/*
 *  OpenSCAD Shapes Library (www.openscad.org)
 *  Copyright (C) 2009  Catarina Mota
 *  Copyright (C) 2010  Elmo Mäntynen
 *
 *  License: LGPL 2.1 or later
*/

/* Extracted from OpenSCAD Library */

// size is a vector [w, h, d]
module roundedBox(width, height, depth, radius) {
  size=[width, height, depth];
  cube(size - [2*radius,0,0], true);
  cube(size - [0,2*radius,0], true);
  for (x = [radius-size[0]/2, -radius+size[0]/2],
       y = [radius-size[1]/2, -radius+size[1]/2]) {
    translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
  }
}
"""


def generateScadFile(x, y, z, boarder, ps_x, ps_y, dxf_name, scad_name ):
    magic_scaler = 0.013888 # Convert ps ouutput to OpenScad units.
    target_x = x - boarder*2.0
    target_y = y - boarder*2.0
    x_offset = 0
    y_offset = 0
    if y==0:
        target_y = (ps_y/(ps_x*1.0)) * target_x * 1.0
        scale_t_x = target_x / (ps_x * magic_scaler)
        scale_t_y = scale_t_x
        y = (target_y + (boarder*2.0))
    else:
        # Determine if letters are Taller and thinner than sign backplate or shorter and fatter than sign backplate
        if (ps_x/(ps_y*1.0)) > (target_x/target_y):
            scale_t_x = target_x / (ps_x * magic_scaler)
            scale_t_y = scale_t_x
            y_offset = (target_y - (ps_y * magic_scaler * scale_t_y))/2
        else:
            scale_t_y = target_y / (ps_y * magic_scaler)
            scale_t_x = scale_t_y
            x_offset = (target_x - (ps_x * magic_scaler * scale_t_x))/2

    scale_t_z = z/2.0
    scad_text = "// High Quality \n$fn=30;\n"
    scad_text = scad_text + "\n\n// DXF File containing the text\n"
    scad_text = scad_text + "translate([" + str(boarder + x_offset) + ", " + str(boarder + y_offset) + ", " + str(z/2.0 + z/4.0 ) + "]) " 
    scad_text = scad_text + "\n    scale([" + str(scale_t_x) + ", " + str(scale_t_y) + ", " + str(scale_t_z) + "]) "
    scad_text = scad_text + "\n        dxf_linear_extrude(file = \"" + dxf_name + "\", height = 1, center = true); "
    scad_text = scad_text + "\n        // linear_extrude() needs to replace dxf_linear_extrude() on next version, as dxf_linear_extrude() is now deprecated"
    scad_text = scad_text + "\n\n// Rounded Box \n"
    scad_text = scad_text + "translate([" + str(x/2.0) + "," + str(y/2.0) + "," + str(z/4.0) +  "])  " 
    scad_text = scad_text + "    roundedBox(" + str(x) + "," + str(y) + "," + str(z/2.0) +  ", " +  str(z/2.0) + ");" 
    scad_text = scad_text + "\n\n\n" 
    scad_text = scad_text + includeRoundedBox()
    f=open(scad_name, 'w')
    f.write(scad_text)
    f.close()


def generateSVG(text, font):
    svg_file = tempfile.NamedTemporaryFile(suffix='.svg')
    svg = """
    <svg xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink">
        <text x="0" y="0" fill="green" font-size="12" style="font-family: """
    svg = svg + str(font) + ";\">\n"
    for line in text.split("\n"):
        svg = svg + "        <tspan x=\"0\" dy=\"12\">" + line + "</tspan>\n"
    svg = svg + "        </text>\n    </svg>\n"
    f=open(svg_file.name, 'w')
    f.write(svg)
    f.close()
    return svg_file


def generateEPSFile(svg_file_name):
    eps_file = tempfile.NamedTemporaryFile(suffix='.ps')
    proc = Popen(['inkscape', svg_file_name, '--export-eps=' + eps_file.name, '--export-text-to-path'], stdout=PIPE, stderr=PIPE)
    proc.wait()
    return eps_file

def generatePNGFile(png_file_name, text, font, width=550):
    svg_file = generateSVG(text, font)
    proc = Popen(['inkscape', svg_file.name, '--export-png=' + png_file_name, '--export-text-to-path', '--export-area-drawing', '--export-width=' + str(width)], stdout=PIPE, stderr=PIPE)
    proc.wait()


def generateDXFFile(dxf_file, text, font):
    svg_file = generateSVG(text, font)
    eps_file = generateEPSFile(svg_file.name)
    proc = Popen(['identify', '-format', '%wx%h' , eps_file.name], stdout=PIPE, stderr=PIPE)
    size = proc.stdout.read().split('x')
    ps_x = int(size[0])
    ps_y = int(size[1])
    proc = Popen(['pstoedit', '-f', 'dxf_s:-splineaspolyline', eps_file.name], stdout=PIPE, stderr=PIPE)
    dxf = proc.stdout.read()
    f=open(dxf_file, 'w')
    f.write(dxf)
    f.close()
    return ps_x, ps_y


def generateZIPFile(zip_file, scad_output, dxf_output):
    zf = zipfile.ZipFile(zip_file, mode='w')
    try:
        zf.write(scad_output)
        zf.write(dxf_output)
    finally:
        zf.close()


def main():
    usage = """usage: %prog [options] \n 
--text=\"Text on sign\" \n
--x=sign_size_x \n
--y=sign_size_y \n
--z=sign_size_z \n
--boarder=size_of_boarder_between_edge_and_letters \n


%prog --help for all options
"""
    parser = OptionParser(usage, version="%prog ")
    parser.add_option("-t", "--text", dest="text",
                      help="The text to put on the sign")
    parser.add_option("-x", "--x", dest="x",
                      help="The size x")
    parser.add_option("-y", "--y", dest="y",
                      help="The size y (the letter go up the y-axis)")
    parser.add_option("-z", "--z", dest="z",
                      help="The size z")
    parser.add_option("-d", "--dxf_output", dest="dxf_output",
                      help="Output dxf file")
    parser.add_option("-s", "--scad_output", dest="scad_output",
                      help="Output scad file")
    parser.add_option("-b", "--boarder", dest="boarder",
                      help="Size of boarder between edge and letters")
    parser.add_option("-f", "--font", dest="font",
                      help="Name of fault to use default FreeSans")    
    parser.add_option("-i", "--zip", dest="zip",
                      help="Name of zip file, to contain openScad file and dxf file.")    
    (options, args) = parser.parse_args() 
    if not options.text:
        parser.error("Must set at least text")
    if not options.dxf_output:
        parser.error("Must set dxf_filename")
    if not options.scad_output:
        parser.error("Must set scad_filename")
    if not options.x:
        x = 3
    else:
        x = int(options.x)
    if not options.y:
        y = 10
    else:
        y = int(options.y)
    if not options.z:
        z = 2
    else:
        z = int(options.z)
    if not options.boarder:
        boarder = 1
    else:
        boarder = int(options.boarder)
    if not options.font:
        font = "FreeSans"
    else:
        font = options.font

    ps_x, ps_y = generateDXFFile(options.dxf_output, options.text, font)
    generateScadFile(x, y, z, boarder, ps_x, ps_y, options.dxf_output, options.scad_output)

    generatePNGFile('/tmp/texxx.png', options.text, font)

    if options.zip:
        generateZIPFile(options.zip, options.scad_output, options.dxf_output)



if __name__ == "__main__":
    main()

